package biback.domain.cash

import biback.domain._
import biback.domain.account.BalanceChangeType
import biback.domain.common.model.Currency
import biback.utils.DomainObject

case class TellerBox
(
  teller: TellerNo,
  status: BoxStatus,
  currencies: Map[Currency, CashBox] = Map.empty[Currency, CashBox],
  vouchers: Map[VoucherType, List[VoucherBox]] = Map.empty[VoucherType, List[VoucherBox]]
) extends DomainObject {

  import BalanceChangeType._
  import BoxStatus._

  def onCommand(c: BoxCashDeposit): CommandResult[c.ReplyType, BoxBalanceChanged] = {
    val b = currencies.getOrElse(c.ccy, CashBox())
    for {
      _ <- status == Using ?= InvalidStatus
    } yield BoxBalanceChanged(c.ctx, c.ccy, b.balance, `+`, c.amount, b.balance + c.amount)
  }

  def onCommand(c: BoxCashWithdraw): CommandResult[c.ReplyType, BoxBalanceChanged] = {
    for {
      _ <- status == Using ?= InvalidStatus
      b <- currencies.get(c.ccy).toRight(CashBoxNotFound(c.ccy))
      _ <- b.balance >= c.amount ?= CashBoxNotEnough(c.ccy)
    } yield BoxBalanceChanged(c.ctx, c.ccy, b.balance, `-`, c.amount, b.balance - c.amount)
  }

  def onEvent(e: BoxBalanceChanged): TellerBox = {
    val box = currencies.getOrElse(e.ccy, CashBox())
    assert(box.balance == e.balancePre)
    val boxX = box.copy(balance = e.balance)
    copy(currencies = currencies.updated(e.ccy, boxX))
  }

  def onCommand(c: BoxRequire): CommandResult[c.ReplyType, BoxRequired] = {
    for {
      _ <- status == TurnIn ?= InvalidStatus
    } yield BoxRequired()
  }

  def onEvent(e: BoxRequired): TellerBox =
    copy(status = Using)
}

case class CashBox(balance: BiDec = BiDec0, cash: Map[Cash, Int] = Map.empty[Cash, Int])

case class VoucherBox(voucherNoFrom: PoInt, voucherNoTo: PoInt)
